home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / usermenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-08-19  |  9.9 KB  |  377 lines

  1. /* usermenu.c- user defined menu
  2.  *
  3.  *  Window Maker window manager
  4.  *
  5.  *  Copyright (c) hmmm... Should I put everybody's name here?
  6.  *  Where's my lawyer?? -- ]d :D
  7.  *
  8.  *  This program is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2 of the License, or
  11.  *  (at your option) any later version.
  12.  *
  13.  *  This program is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with this program; if not, write to the Free Software
  20.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  21.  *  USA.
  22.  * 
  23.  * * * * * * * * *
  24.  * User defined menu is good, but beer's always better
  25.  * if someone wanna start hacking something, He heard...
  26.  * TODO
  27.  *  - enhance commands. (eg, exit, hide, list all app's member
  28.  *    window and etc)
  29.  *  - cache menu... dunno.. if people really use this feature :P
  30.  *  - Violins, senseless violins!
  31.  *  that's all, right now :P
  32.  *  - external! WINGs menu editor.
  33.  *  TODONOT
  34.  *  - allow applications to share their menu. ] think it
  35.  *    looks wierd since there still are more than 1 appicon.
  36.  *  
  37.  *  Syntax...
  38.  *  (
  39.  *    "Program Name",
  40.  *    ("Command 1", SHORTCUT, 1),
  41.  *    ("Command 2", SHORTCUT, 2, ("Allowed_instant_1", "Allowed_instant_2")),
  42.  *    ("Command 3", SHORTCUT, (3,4,5), ("Allowed_instant_1")),
  43.  *    (
  44.  *      "Submenu",
  45.  *      ("Kill Command", KILL),
  46.  *      ("Hide Command", HIDE),
  47.  *      ("Hide Others Command", HIDE_OTHERS),
  48.  *      ("Members", MEMBERS),
  49.  *      ("Exit Command", EXIT)
  50.  *    )
  51.  *  )
  52.  *  
  53.  *  Tips:
  54.  *  - If you don't want short cut keys to be listed
  55.  *    in the right side of entries, you can just put them
  56.  *    in array instead of using the string directly.
  57.  *  
  58.  */
  59.  
  60. #include "wconfig.h"
  61.  
  62. #ifdef USER_MENU
  63.  
  64. #include <X11/Xlib.h>
  65. #include <X11/Xutil.h>
  66. #include <X11/Xproto.h>
  67. #include <X11/Xatom.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <stdio.h>
  71. #include <unistd.h>
  72.  
  73. #include "WindowMaker.h"
  74. #include "wcore.h"
  75. #include "menu.h"
  76. #include "actions.h"
  77. #include "funcs.h"
  78. #include "keybind.h"
  79.  
  80. #include "framewin.h"
  81.  
  82.  
  83. extern proplist_t ReadProplistFromFile(char *file);
  84. /*** var ***/
  85. extern WPreferences wPreferences;
  86.  
  87. typedef struct {
  88.     WScreen *screen;
  89.     WShortKey *key;
  90.     int key_no;
  91. } WUserMenuData;
  92.  
  93.  
  94. static void
  95. notifyClient(WMenu *menu, WMenuEntry *entry)
  96. {
  97.     XEvent event;
  98.     WUserMenuData *data = entry->clientdata;
  99.     WScreen *scr = data->screen;
  100.     Window window;
  101.     int i;
  102.  
  103.     window=scr->focused_window->client_win;
  104.  
  105.     for(i=0;i<data->key_no;i++) {
  106.         event.xkey.type = KeyPress;
  107.         event.xkey.display = dpy;
  108.         event.xkey.window = window;
  109.         event.xkey.root = DefaultRootWindow(dpy);
  110.         event.xkey.subwindow = (Window)None;
  111.         event.xkey.x = 0x0;
  112.         event.xkey.y = 0x0;
  113.         event.xkey.x_root = 0x0;
  114.         event.xkey.y_root = 0x0;
  115.         event.xkey.keycode = data->key[i].keycode;
  116.         event.xkey.state = data->key[i].modifier;
  117.         event.xkey.same_screen = True;
  118.         event.xkey.time = CurrentTime;
  119.         if (XSendEvent(dpy, window, False, KeyPressMask, &event)) {
  120.             event.xkey.type = KeyRelease;
  121.             event.xkey.time = CurrentTime;
  122.             XSendEvent(dpy, window, True, KeyReleaseMask, &event);
  123.         }
  124.     }
  125. }
  126.  
  127. static void
  128. removeUserMenudata(void *menudata)
  129. {
  130.     WUserMenuData *data = menudata;
  131.     if(data->key) free(data->key);
  132.     free(data);
  133. }
  134.  
  135.  
  136. static WUserMenuData*
  137. convertShortcuts(WScreen *scr, proplist_t shortcut)
  138. {
  139.     WUserMenuData *data;
  140.     KeySym ksym;
  141.     char *k;
  142.     char *buffer;
  143.     char buf[128], *b;
  144.     int keycount,i,j,mod;
  145.  
  146.     if (PLIsString(shortcut)) {
  147.         keycount = 1;
  148.     }
  149.     else if (PLIsArray(shortcut)) {
  150.         keycount = PLGetNumberOfElements(shortcut);
  151.     }
  152.     else return NULL;
  153.     /*for (i=0;i<keycount;i++){*/
  154.  
  155.     data = wmalloc(sizeof(WUserMenuData));
  156.     if (!data) return NULL;
  157.     data->key = wmalloc(sizeof(WShortKey)*keycount);
  158.     if (!data->key) {
  159.         free(data);
  160.         return NULL;
  161.     }
  162.  
  163.  
  164.     for (i=0,j=0;i<keycount;i++) {
  165.         data->key[j].modifier = 0;
  166.         if (PLIsArray(shortcut)) {
  167.             strcpy(buf, PLGetString(PLGetArrayElement(shortcut, i)));
  168.         } else {
  169.             strcpy(buf, PLGetString(shortcut));
  170.         }
  171.         b = (char*)buf;
  172.  
  173.         while ((k = strchr(b, '+'))!=NULL) {
  174.             *k = 0;
  175.             mod = wXModifierFromKey(b);
  176.             if (mod<0) {
  177.                 break;
  178.             }
  179.             data->key[j].modifier |= mod;
  180.             b = k+1;
  181.         }
  182.  
  183.         ksym = XStringToKeysym(b);
  184.         if (ksym==NoSymbol) {
  185.             continue;
  186.         }
  187.  
  188.         data->key[j].keycode = XKeysymToKeycode(dpy, ksym);
  189.         if (data->key[j].keycode) {
  190.             j++;
  191.         }
  192.     }
  193.  
  194. keyover:
  195.     
  196.     /* get key */
  197.     if (!j) {
  198.         puts("fatal j");
  199.         free(data->key);
  200.         free(data);
  201.         return NULL;
  202.     }
  203.     data->key_no = j;
  204.     data->screen = scr;
  205.     
  206.     return data;
  207. }
  208.  
  209. static WMenu*
  210. configureUserMenu(WScreen *scr, proplist_t plum)
  211. {
  212.     char *mtitle;
  213.     WMenu *menu=NULL;
  214.     proplist_t elem, title, command, params;
  215.     int count,i;
  216.     WUserMenuData *data;
  217.  
  218.     if (!plum) return NULL;
  219.     if (!PLIsArray(plum)) {
  220.         return NULL;
  221.     }
  222.  
  223.     count = PLGetNumberOfElements(plum);
  224.     if (!count) return NULL;
  225.  
  226.     elem = PLGetArrayElement(plum, 0);
  227.     if (!PLIsString(elem)) {
  228.         return NULL;
  229.     }
  230.     
  231.     mtitle = PLGetString(elem);
  232.     
  233.     menu=wMenuCreateForApp(scr, mtitle, True);
  234.     
  235.     for(i=1; i<count; i++) {
  236.         elem = PLGetArrayElement(plum,i);
  237.         if(PLIsArray(PLGetArrayElement(elem,1))) {
  238.             WMenu *submenu;
  239.             WMenuEntry *mentry;
  240.             
  241.             submenu = configureUserMenu(scr,elem);
  242.             if (submenu)
  243.                 mentry = wMenuAddCallback(menu, submenu->frame->title,
  244.                         NULL, NULL);
  245.             wMenuEntrySetCascade(menu, mentry, submenu);
  246.         }
  247.         else {
  248.             int idx = 0;
  249.             proplist_t instances=0;
  250.  
  251.             title = PLGetArrayElement(elem,idx++);
  252.             command = PLGetArrayElement(elem,idx++);
  253.             if (PLGetNumberOfElements(elem) >= 3)
  254.                 params = PLGetArrayElement(elem,idx++);
  255.             
  256.             if (!title || !command)
  257.                 return menu;
  258.  
  259.             if (!strcmp("SHORTCUT",PLGetString(command))) {
  260.                 WMenuEntry *entry;
  261.  
  262.                 data = convertShortcuts(scr, params);
  263.                 if (data){
  264.                     entry = wMenuAddCallback(menu, PLGetString(title),
  265.                                     notifyClient, data);
  266.  
  267.                     if (entry) {
  268.                         if (PLIsString(params)) {
  269.                             entry->rtext = GetShortcutString(PLGetString(params));
  270.                         }
  271.                         entry->free_cdata = removeUserMenudata;
  272.  
  273.                         if (PLGetNumberOfElements(elem) >= 4) {
  274.                             instances = PLGetArrayElement(elem,idx++);
  275.                             if(PLIsArray(instances))
  276.                 if (instances && PLGetNumberOfElements(instances)
  277.                     && PLIsArray(instances)){
  278.                     entry->instances = PLRetain(instances);
  279.                             }
  280.                         }
  281.                     }
  282.                 }
  283.             }
  284.  
  285.  
  286.         }
  287.     }
  288.     return menu;
  289. }
  290.  
  291. void
  292. wUserMenuRefreshInstances(WMenu *menu, WWindow *wwin)
  293. {
  294.     WMenuEntry* entry;
  295.     int i,j,count,paintflag;
  296.     
  297.     paintflag=0;
  298.     
  299.     if(!menu) return;
  300.  
  301.     for (i=0; i<menu->entry_no; i++) {
  302.         if (menu->entries[i]->instances){
  303.             proplist_t ins;
  304.             int oldflag;
  305.             count = PLGetNumberOfElements(menu->entries[i]->instances);
  306.  
  307.             oldflag = menu->entries[i]->flags.enabled;
  308.             menu->entries[i]->flags.enabled = 0;
  309.             for (j=0; j<count;j++) {
  310.                 ins = PLGetArrayElement(menu->entries[i]->instances,j);
  311.                 if (!strcmp(wwin->wm_instance,PLGetString(ins))) {
  312.                     menu->entries[i]->flags.enabled = 1;
  313.                     break;
  314.                 }
  315.             }
  316.             if (oldflag != menu->entries[i]->flags.enabled)
  317.                 paintflag=1;
  318.         }
  319.     }
  320.     for (i=0; i < menu->cascade_no; i++) {
  321.         if (!menu->cascades[i]->flags.brother)
  322.         wUserMenuRefreshInstances(menu->cascades[i], wwin);
  323.         else
  324.         wUserMenuRefreshInstances(menu->cascades[i]->brother, wwin);
  325.     }
  326.  
  327.     if (paintflag)
  328.         wMenuPaint(menu);
  329. }
  330.  
  331.  
  332. static WMenu*
  333. readUserMenuFile(WScreen *scr, char *file_name)
  334. {
  335.     WMenu *menu;
  336.     char *mtitle;
  337.     proplist_t plum, elem, title, command, params;
  338.     int count,i;
  339.  
  340.     menu=NULL;
  341.     plum = ReadProplistFromFile(file_name);
  342.     /**/
  343.     
  344.     if(plum){
  345.         menu = configureUserMenu(scr, plum);
  346.         PLRelease(plum);
  347.     }
  348.     return menu;
  349. }
  350.  
  351.  
  352. WMenu*
  353. wUserMenuGet(WScreen *scr, WWindow *wwin)
  354. {
  355.     WMenu *menu = NULL;
  356.     char buffer[100];
  357.     char *path = NULL;
  358.     char *tmp;
  359.     if ( wwin->wm_instance && wwin->wm_class ) {
  360.         tmp=wmalloc(strlen(wwin->wm_instance)+strlen(wwin->wm_class)+7);
  361.         sprintf(tmp,"%s.%s.menu",wwin->wm_instance,wwin->wm_class);
  362.         path = wfindfile(DEF_USER_MENU_PATHS,tmp);
  363.         free(tmp);
  364.  
  365.         if (!path) return NULL;
  366.         
  367.         if (wwin) {
  368.             menu = readUserMenuFile(scr, path);
  369.         }
  370.  
  371.         free(path);
  372.     }
  373.     return menu;
  374. }
  375.  
  376. #endif /* USER_MENU */
  377.